package rapc;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;

/**
 *
 * @author moi
 */
public class EnsembleCas {

    private ArrayList<cas> ensemble_cas;

    public EnsembleCas(ArrayList<cas> c) {
        this.ensemble_cas = c;
    }

    public ArrayList<cas> getensemble_cas() {
        return ensemble_cas;
    }

    public ArrayList<Integer> getVoisin(cas cible, float T, int K) {
        // T est le seuil (Threshold) de similarité minimum pour être considéré comme voisin de ce cas cible
        //donc le rayon du cercle sur les dessins.
        // K représente le nombre de cas voisins nécessaire et
        //suffisant pour qu'une classe de solution soit éligible comme candidate pour la solution cible
        // il servirait pour l'attribution par adaptation d'un descripteur inconnu du cas cible
        int plusProche;
        float plusProcheValeur = 0;
        float similarite = 0;
        ArrayList<Integer> liste_cas_voisins = new ArrayList<Integer>(); // la liste est vide au départ
       /*  System.out.println("cible:"+cible.TosString());
        for(int i=0;i<ensemble_cas.size();i++)
        {
        System.out.println("cas:"+i+":"+ensemble_cas.get(i).TosString());
        
        }*/


        for (int i = 0; i < this.ensemble_cas.size(); i++) {
            similarite = similarite(cible, ensemble_cas.get(i));
            //Comparer la description du cas cible avec la description du cas source suivant de la base de cas
            // et ajout dans la liste des cas voisin si assez proche.
            System.out.println("la similaritié entre le cas" + i + "et le cas cible" + similarite(cible, ensemble_cas.get(i)) + "\n");
            if (similarite >= T) {
                liste_cas_voisins.add(i);
                if (plusProcheValeur < similarite) {
                    plusProche = i;
                    plusProcheValeur = similarite;
                }

            }
        }

        if (liste_cas_voisins.isEmpty()) {
            System.out.println("Manque d'expérience pour ce type de cas cible \n");
            return liste_cas_voisins;
            //manque d'expérience pour ce type de cas cible
        }
        //return liste_cas_voisins.get(plusProche) si on veu juste le plus proche

        return liste_cas_voisins;
    }

    //les deux cas doivent avoir le meme
    //nombre et les meme type de descripteur
     public float similarite(cas a, cas b)
    {   float sommePoid=0;
        float similarite=0;

        for(int i = 0; i<a.getDescripteur().size();i++)
        {
      System.out.println("les descripteur des cas dans similaritÃ© cas:"+a.TosString()+"b:"+b.TosString());

     System.out.print("le poid de ce descripteur"+(a.getDescripteur().get(i).getPoids()));
     similarite =  (similarite +a.getDescripteur().get(i).getPoids()* a.getDescripteur().get(i).similariteDescripteur(a.getDescripteur().get(i), b.getDescripteur().get(i),
        a.getDescripteurCase().get(i),  b.getDescripteurCase().get(i)    ));
    sommePoid=sommePoid+a.getDescripteur().get(i).getPoids();
        }
          System.out.println("similarité cas:"+a.TosString() +"vs cas:"+b.TosString()+":"+similarite/sommePoid +"\n");
        return similarite/sommePoid;
     }

    public  ArrayList<Float> getSimilarite(cas cible)
    {
        float similarite=0;
         ArrayList<Float> liste_similarite= new ArrayList<Float>(); // la liste est vide au dÃ©part
         for(int i=0; i<this.ensemble_cas.size();i++ )
        {similarite=similarite(cible, ensemble_cas.get(i));
         System.out.println("la similaritiÃ© entre le cas"+i+"et le cas cible"+ similarite(cible, ensemble_cas.get(i))+ "\n");
         liste_similarite.add(similarite);
        }
         return liste_similarite;

      }




        public  int adaptation(cas cible,float T,int K, ArrayList<Integer> descripteur_Inconnu)
    {
        // T est le seuil (Threshold) de similaritÃ© minimum pour Ãªtre considÃ©rÃ© comme voisin de ce cas cible
        //donc le rayon du cercle sur les dessins.
        // K reprÃ©sente le nombre de cas voisins nÃ©cessaire et
        //suffisant pour qu'une classe de solution soit Ã©ligible comme candidate pour la solution cible
        // il servirait pour l'attribution par adaptation d'un descripteur inconnu du cas cible
        int plusProche=-1;
        float plusProcheValeur=0;
        float similarite=0;



        for(int i=0; i<this.ensemble_cas.size();i++ )
        {similarite=similarite(cible, ensemble_cas.get(i),descripteur_Inconnu);
         //Comparer la description du cas cible avec la description du cas source suivant de la base de cas
         // et ajout dans la liste des cas voisin si assez proche.
         System.out.println("la similaritié entre le cas"+i+"et le cas cible"+ similarite+ "\n");
             if ( similarite >= T)
                  {

                      if(plusProcheValeur < similarite)
                      {
                          plusProche = i;
                          plusProcheValeur= similarite;
                      }

                  }
        }

        if (plusProche==-1)
        {
            System.out.println("Manque d'expÃ©rience pour ce type de cas cible \n");
            return -1;

        }
         for(int i=0; i<descripteur_Inconnu.size();i++ )
         {
             cible.setescripteurCas(ensemble_cas.get(plusProche).getDescripteurCase().get(descripteur_Inconnu.get(i)), descripteur_Inconnu.get(i));
              System.out.println("changement de: "+ensemble_cas.get(plusProche).getDescripteurCase().get(descripteur_Inconnu.get(i)));
         }
        return 1;


    }
         public float similarite(cas cible, cas get, ArrayList<Integer> descripteur_Inconnu) {
    float sommePoid=0;
        float similarite=0;

        for(int i = 0; i<get.getDescripteur().size();i++)
        {if(!descripteur_Inconnu.contains(i))
                {
     System.out.println("les descripteur des cas dans similarité cas:"+get.TosString()+"b:"+cible.TosString());
     System.out.print("le poid de ce descripteur"+(get.getDescripteur().get(i).getPoids()));
     similarite =  (similarite +get.getDescripteur().get(i).getPoids()* get.getDescripteur().get(i).similariteDescripteur(get.getDescripteur().get(i), cible.getDescripteur().get(i),
        get.getDescripteurCase().get(i),  cible.getDescripteurCase().get(i)    ));
     sommePoid=sommePoid+get.getDescripteur().get(i).getPoids();
            }
        }

        System.out.println("similarité cas:"+get.TosString() +"vs cas:"+cible.TosString()+":"+similarite/sommePoid +"\n");
        return similarite/sommePoid;
    }

    //prend en parametre un chemin avec un nom et sauvegarde
    public void save(String Chemin) throws IOException {

        File f = new File(Chemin);// créetion du fichier          
        f.createNewFile();

        FileWriter fstream = new FileWriter(f);//buffer du fichier          
        BufferedWriter print = new BufferedWriter(fstream);

        for (int i = 0; i < ensemble_cas.size(); i++) {

            //premier passage on sauvegarde la stucture des cas
            if (i == 0) {
                ArrayList<descripteur> desc = new ArrayList<descripteur>();
                desc = ensemble_cas.get(i).getDescripteur();

                //on dis que c'est des descripteurs
                print.write("#descriptors#");
                print.newLine();
                for (int j = 0; j < desc.size(); j++) {

                    print.write(desc.get(j).toString());
                    print.newLine();

                }

                //mainetant on indique que c'est des cas
                print.write("#cases#");
                print.newLine();
            }


            print.write(ensemble_cas.get(i).TosString());
            print.newLine();
        }

        print.close();
    }

    //prend en parametre un chemin avec un nom et sauvegarde
    public void open(String Chemin) throws IOException {



        String x = Chemin;


        if (x == null) {
            return;
        }


        File f = new File(x);
        if (x == null) {
            return;
        }

        if (!f.exists()) {
            return;
        }

        if (f != null) {

            FileInputStream fstream = new FileInputStream(f);
            DataInputStream in = new DataInputStream(fstream);
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String strLine;
            String type = "";


            ArrayList<descripteur> descripteurs = new ArrayList<descripteur>();

            boolean descriptor = false;
            boolean cases = false;

            while ((strLine = br.readLine()) != null) {

                //evite de rentrer le mot clef "#cases#"   
                if (strLine.equals("#cases#") || cases) {

                    descriptor = false;
                    cases = true;

                    if (!strLine.equals("#cases#")) {

                        cas moncas = new cas();

                        //tableau de valeur
                        String[] split = strLine.split(",");
                        ArrayList<String> tableau = new ArrayList<String>(Arrays.asList(split));
                        
                        System.out.println(descripteurs.size());

                        //on enregistre les tableau contenant les descripteuirs et les valeur
                        moncas.addListedescripteur(descripteurs);
                        moncas.addListeCas(tableau);

                        ensemble_cas.add(moncas);
                    }

                }

                if (strLine.equals("#descriptors#") || descriptor) {
                    descriptor = true;
                    cases = false;
                    //System.out.println(strLine);
                    
                    //evite de rentrer le mot clef  #descriptors#             
                    if (!strLine.equals("#descriptors#")) {

                        String[] split = strLine.split(";");
                        type = split[split.length - 1];


                        if (type.equals("Boolean")) {
                            //booléen

                            descripteurBool monbool = new descripteurBool();

                            monbool.setCaseId(split[0]);
                            monbool.setNom(split[1]);
                            monbool.setExplication(split[2]);
                            monbool.setNorm(Boolean.parseBoolean(split[3]));
                            monbool.setdefVal(Boolean.parseBoolean(split[4]));
                            monbool.Poids(Float.parseFloat(split[5]));

                            descripteurs.add(monbool);



                        }
                        if (type.equals("Numerique")) {

                            descripteurNumerique monum = new descripteurNumerique();


                            monum.setCaseId(split[0]);
                            monum.setNom(split[1]);
                            monum.setExplication(split[2]);
                            monum.setNorm(Double.parseDouble(split[3]));
                            monum.setMin(Double.parseDouble(split[4]));
                            monum.setMax(Double.parseDouble(split[5]));
                            monum.setDefault(Double.parseDouble(split[6]));
                            monum.Poids(Float.parseFloat(split[7]));

                            descripteurs.add(monum);

                        }
                        if (type.equals("String")) {

                            descripteurString monstring = new descripteurString();

                            monstring.setCaseId(split[0]);
                            monstring.setNom(split[1]);
                            monstring.setExplication(split[2]);
                            monstring.setDefault(split[3]);
                            monstring.setNormal(split[4]);
                            monstring.Poids(Float.parseFloat(split[5]));

                            descripteurs.add(monstring);
                        }
                    }
                }
            }
        }

    }

    public String TosString() {

        String chaine = "";

        for (int i = 0; i < ensemble_cas.size(); i++) {
            chaine += ensemble_cas.get(i).TosString();
            chaine += ",";
        }



        return chaine;//un cas au format string
    }
}
